package com.broada.apm.logic.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.base.BaseLogic;
import com.broada.apm.cache.AreaManager;
import com.broada.apm.cache.ErrorManager;
import com.broada.apm.cache.ThresholdTypeManager;
import com.broada.apm.entity.ConfigVariable;
import com.broada.apm.entity.IPLocation;
import com.broada.apm.entity.NoticeCommandException;
import com.broada.apm.entity.ThresholdType;
import com.broada.apm.entity.convert.BeanConvert;
import com.broada.apm.es.bean.ClusterInfo;
import com.broada.apm.es.indices.service.IndexService;
import com.broada.apm.es.indices.service.impl.IndexServiceImpl;
import com.broada.apm.es.indices.support.PerfIndicesBuilder;
import com.broada.apm.indicator.api.ApmClientFactory;
import com.broada.apm.indicator.api.common.ApmDataIndicatorException;
import com.broada.apm.indicator.api.common.IllegalIPAddressException;
import com.broada.apm.indicator.api.common.UserAlreadyExistException;
import com.broada.apm.indicator.api.model.Variable;
import com.broada.apm.logic.ConfigLogic;
import com.broada.apm.model.ConfigItem;
import com.broada.apm.model.Dimension.Area;
import com.broada.apm.model.Dimension.Error;
import com.broada.apm.model.L7Module;
import com.broada.apm.model.PagingList;
import com.broada.apm.model.User;
import com.broada.apm.protocol.L7ModuleManager;
import com.broada.apm.protocol.L7ModuleParser.L7ModuleDescr;
import com.broada.apm.service.internal.IndicatorService;
import com.broada.apm.service.internal.impl.IndicatorServiceImpl;
import com.broada.apm.util.CacheRefreshUtil;
import com.broada.apm.util.JsonUtil;
import com.broada.apm.util.MD5Util;
import com.broada.apm.utils.ApmFileUtils;
import com.broada.apm.utils.ExceptionUtils;
import com.broada.apm.utils.IPUtils;
import com.google.common.base.Function;
import com.google.common.collect.Lists;

public class ConfigLogicImpl extends BaseLogic implements ConfigLogic {

	private Logger log = LoggerFactory.getLogger(ConfigLogicImpl.class);
	private PerfIndicesBuilder builder = PerfIndicesBuilder.getInstance();
	private IndexService indexService = new IndexServiceImpl();
	private IndicatorService indicatorService = new IndicatorServiceImpl();
	
	@Override
	public void addConfigData(ConfigVariable variable)
			throws ApmDataIndicatorException, NoticeCommandException {
		if (variable != null) {
			int confType = variable.getConfType();
			Variable[] varConf = variable.getConfData();
			
			for(Variable var : varConf) {
				String key = variable.getSettingKey(var.getId());
				String value = (String) var.getItem().get("value");
				ConfigItem configItem = new ConfigItem(key, value);
				if(key != null) {
//					if (4 == confType && key.equals("filter.rules")){
//						if (value != null) {
//							filterList.addAll(setFilter(value));
//						}
//					} else {
						configItemService.updateConfigItem(configItem);
//					}
				}
			}
//			if (4 == confType) {
//				configItemService.saveFilter(filterList);
//				L7ModuleManager.filterPackage();
//			}   4的处理移至别处
			if (5 == confType)
				indicatorService.NoticeCommand("reload", "alertforward");
			if (6 == confType) {
				if ("1".equals(variable.getIsDedicate()))
					indicatorService.NoticeCommand("enable", "globalarea");
				if ("0".equals(variable.getIsDedicate()))
					indicatorService.NoticeCommand("disable", "globalarea");
			}
			if ("true".equals(variable.getResetToFactory())) {
				logoReset();
			}
		}
	}

	@Override
	public List<ConfigItem> queryConfigData(String confItem)
			throws ApmDataIndicatorException {
		List<ConfigItem> confs = configItemService.getConfigItemLikeKey(confItem);
		// 数据包过滤移至别处
//		if (confItem.equals("filter")) {
//			ConfigItem configItem = new ConfigItem();
//			List<FilterRule> filters = configItemService.getAllFiltersJson();
//			StringBuffer filterJson = new StringBuffer();
//			filterJson.append("[");
//			int i = 0;
//			for (FilterRule filter : filters) {
//				if (i > 0) {
//					filterJson.append(",");
//				}
//				i++;
//				filterJson.append("{\"ip\":\"");
//				filterJson.append(filter.getIp());
//				filterJson.append("\",\"port\":\"");
//				filterJson.append(filter.getPort());
//				filterJson.append("\",\"policys\":\"");
//				filterJson.append(filter.getPolicys());
//				filterJson.append("\"}");
//			}
//			filterJson.append("]");
//			configItem.setKey("filter.rules");
//			configItem.setValue(filterJson.toString());
//			confs.add(configItem);
//		}
		List<ConfigItem> sets = Lists.newArrayList();
		if (confs != null)
			sets.addAll(confs);
		return sets;
	}

	@Override
	public void updateLib() {
		
	}

	@Override
	public PagingList<User> queryUser(int pageIndex, int pageSize)
			throws ApmDataIndicatorException {
		PagingList<User> users = userService.getPagingUser(pageIndex, pageSize);
		return users;
	}

	@Override
	public User queryUserByAccount(String account)
			throws ApmDataIndicatorException {
		return userService.getUserByAccount(account);
	}

	@Override
	public void addUser(User user) throws Exception {
		User exist = queryUserByAccount(user.getAccount());
		if (exist != null) {
			throw new UserAlreadyExistException("账号已存在,无法添加.");
		}

		String md5pwd = MD5Util.string2MD5(user.getPassword());
		user.setPassword(md5pwd);
		user.setId(UUID.randomUUID().toString());
		userService.addUser(user);
	}

	@Override
	public void updateUser(User user) throws ApmDataIndicatorException {
		userService.updateUserNameAndRole(user.getId(), user.getName(), user.getRole());
	}

	@Override
	public void delUser(String userId) throws ApmDataIndicatorException {
		User user = new User();
		user.setId(userId);
		userService.deleteUser(user);
	}

	@Override
	public void updatePwd(String userId, String oldPass, String newPass)
			throws Exception {
		try {
			User user = userService.getUserById(userId);
			// admin自身密码修改
			if (StringUtils.isNotBlank(oldPass) && StringUtils.isNotBlank(userId)) {
				if (!user.getPassword().equals(MD5Util.string2MD5(oldPass))) {
					throw new Exception("原密码错误，请重新修改。");
				}
			}

			String md5pwd = MD5Util.string2MD5(newPass);
			userService.updateUserPassword(userId, md5pwd);
		} catch (Exception e) {
			ExceptionUtils.error(log, "用户重置密码失败:", e);
			throw new Exception(e.getMessage());
		}
	}

	@Override
	public void updateStatus(String userId, int status) throws Exception {
		userService.updateUserStatus(userId, status);
	}

	@Override
	public List<L7Module> queryL7Module() {
		return L7ModuleManager.queryL7Module();
	}

	@Override
	public void deleteL7Module(String moduleId) throws Exception {
		ApmClientFactory.getApmClient().getIndicatorItemService().deleteMetricsByModuleId(moduleId);
		ApmClientFactory.getApmClient().getIndicatorItemService().deleteL7PanelByModuleId(moduleId);
		ApmClientFactory.getApmClient().getL7moduleMenuService().deleteL7MenuByModuleId(moduleId);
		
		L7Module l7module = l7ModuleService.getL7ModuleById(moduleId);
//		RemoteProtocolInfo info = new RemoteProtocolInfo();
//		info.setL7_proto(l7module.getL7_proto());
//		info.setVersion(l7module.getVersion());
//		l7ModuleService.deleteRemoteProtocolInfo(info);       // 远程状态信息删除
		L7ModuleManager.delL7Module(l7module);
		L7Module l7Module = new L7Module();
		l7Module.setId(moduleId);
		l7ModuleService.deleteL7Module(l7Module);            // 本地删除信息
	}

	@Override
	public void updStatusL7Module(String moduleId, int status) throws Exception {
		if (status == 0) {
		    try{
		        L7ModuleManager.enabledL7Module(moduleId);
		    } catch (Exception e) {
		        throw e;
		    }
		} else {
		    try{
			L7ModuleManager.disableL7Module(moduleId);
		    }catch(Exception e){
		        if(e.getMessage().contains("Moduleis already unregistered")){
		            //....
		        } else {
		            throw e;
		        }
		        
		    }
		}
		L7Module l7Module = new L7Module();
		l7Module.setId(moduleId);
		l7Module.setStatus(status);
		l7ModuleService.updateL7Module(l7Module);
	}

	@Override
	public void setL7ModuleCode(Error error) throws Exception {
		try {
			if (StringUtils.isNotBlank(error.getId())) {
				dimensionService.updateError(error);
				ErrorManager.getInstance().updateError(error);
				indicatorService.NoticeCommand("reload", "returncode");
				CacheRefreshUtil.refresh(CacheRefreshUtil.REFRESH_ERROR_CACHE);
			} else {
				throw new Exception("返回码Id为空，修改失败!");
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, "编辑返回码失败:", e);
			throw new Exception(e.getMessage());
		}
	}

	@Override
	public void addL7ModuleCode(Error error) throws Exception {
		try {
			// 手工添加
			error.setCreateBy(2);
			String id = error.getProtocol() + "." + error.getCode();
			error.setId(id);
			dimensionService.addError(error);
			indicatorService.NoticeCommand("reload", "returncode");
			CacheRefreshUtil.refresh(CacheRefreshUtil.REFRESH_ERROR_CACHE);
		} catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
			throw e;
		} catch (Exception e) {
			ExceptionUtils.error(log, "手工添加失败", e);
			throw e;
		}
	}

	@Override
	public List<Error> queryL7ModuleCode(String moduleId) throws Exception {
		List<Error> listError = null;
		try {
			listError = new ArrayList<Error>();
			if (StringUtils.isNotBlank(moduleId)) {
				int protocol = Integer.parseInt(moduleId);
				listError = dimensionService.getErrorByL7Protocol(protocol);
			} else {
				throw new Exception("moduleId为空，错误码查询错误");
			}
			
		} catch (Exception e) {
			ExceptionUtils.error(log, "错误码查询错误", e);
			throw e;
		}
		return listError;
	}

	@Override
	public void delL7ModuleCode(int protocol, String id, String code,
			String errorMessage) throws Exception {
		Error error = new Error();
		error.setCode(code);
		error.setId(id);
		error.setErrorMessage(errorMessage);
		error.setProtocol(protocol);
		try {
			dimensionService.deleteError(error);
			indicatorService.NoticeCommand("reload", "returncode");
			CacheRefreshUtil.refresh(CacheRefreshUtil.REFRESH_ERROR_CACHE);
		} catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
			throw e;
		}
	}

	@Override
	public List<Area> queryAreaByCode(String areaCode) {
		List<Area> areas = AreaManager.getInstance().queryAreaByCode(areaCode);// TODO
		return areas;
	}

	@Override
	public void saveIPLocation(IPLocation ipLocation)
			throws IllegalIPAddressException, ApmDataIndicatorException,
			NoticeCommandException {
		if ((ipLocation.getStartIp() == null || ipLocation.getStartIp().trim().length() == 0) && 
				(ipLocation.getEndIp() == null || ipLocation.getEndIp().trim().length() == 0)) {
			throw new IllegalIPAddressException("无效的IP地址范围。");
		}
		if (StringUtils.isNotBlank(ipLocation.getStartIp())) {
			ipLocation.setStartIpNum(IPUtils.toLong(ipLocation.getStartIp()));
		}
		if (StringUtils.isNotBlank(ipLocation.getEndIp())) {
			ipLocation.setEndIpNum(IPUtils.toLong(ipLocation.getEndIp()));
		}
		if (StringUtils.isEmpty(ipLocation.getId())) {
			if (StringUtils.isNotBlank(ipLocation.getEndIp())) {
				ipLocation.setId(ipLocation.getStartIp() + "-" + ipLocation.getEndIp());
			} else {
				ipLocation.setId(ipLocation.getStartIp());
			}
		}
		IPLocation ipl = new IPLocation();
		ipl.unwrap().setId(ipLocation.getId());
		List<com.broada.apm.model.IPLocation> ipList = ipLocationService.getIPLocation(ipl.unwrap());
		if(ipList != null && ipList.size() > 0) {
			ipLocationService.updateIPLocation(ipLocation.unwrap());
		} else {
			ipLocationService.addIPLocation(ipLocation.unwrap());
		}
		indicatorService.NoticeCommand("reload", "area");
	}

	@Override
	public void deleteIPLocation(String id) throws ApmDataIndicatorException,
			NoticeCommandException {
		IPLocation ipLocation = new IPLocation();
		ipLocation.setId(id);
		ipLocationService.deleteIPLocation(ipLocation.unwrap());
		indicatorService.NoticeCommand("reload", "area");
	}

	@Override
	public List<IPLocation> queryIPLocation(String ip, String areaCode,
			String memo, String pageIndex, String pageSize) throws ApmDataIndicatorException {
		IPLocation ipLocation = new IPLocation();
		if (!StringUtils.isEmpty(ip)) {
			if (IPUtils.isIp(ip)) {
				ipLocation.setStartIpNum(IPUtils.toLong(ip));
				ipLocation.setEndIpNum(IPUtils.toLong(ip));
			}
			ipLocation.setStartIp(ip);
			ipLocation.setEndIp(ip);
			
		}
		if(StringUtils.isNotBlank(pageIndex)){
			ipLocation.setPageIndex((Integer.valueOf(pageIndex)) * Integer.valueOf(pageSize));
		}
		if(StringUtils.isNotBlank(pageSize)){
			ipLocation.setPageSize(Integer.valueOf(pageSize));
		}
		if (!StringUtils.isEmpty(areaCode))
			ipLocation.setAreaCode(areaCode);
		if (!StringUtils.isEmpty(memo))
			ipLocation.setMemo(memo);
		List<com.broada.apm.model.IPLocation> iPLocations = ipLocationService.getIPLocationByCondition(ipLocation.unwrap());
		List<IPLocation> locations = Lists.transform(iPLocations,
				new Function<com.broada.apm.model.IPLocation, IPLocation>() {
					@Override
					public IPLocation apply(com.broada.apm.model.IPLocation input) {
						return IPLocation.wrap(input);
					}
				});
		
		return locations;
	}

	@Override
	public ClusterInfo historyDiskData() throws ApmDataIndicatorException {
		ClusterInfo cluster = null;
		try {
			cluster = indexService.queryNodeStats();
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "历史数据磁盘容量和使用量查询异常", e);
			throw e;
		}
		return cluster;
	}

	@Override
	public boolean historyCleanData(int time, String appIds) {
		boolean delIndex = true;
		boolean delIndexData = true;
		try {
			// 清除相关索引
			delIndex = builder.clearPerfIndexByAppId(time, appIds.split(","));
			String[] indexs = builder.queryClearPerfIndex(time, "apm_perf_y*");
			if (ArrayUtils.isNotEmpty(indexs)) {
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(new Date());
				calendar.set(Calendar.HOUR_OF_DAY, 0);
				calendar.set(Calendar.MINUTE, 0);
				calendar.set(Calendar.SECOND, 0);
				calendar.set(Calendar.MILLISECOND, 0);
				calendar.add(Calendar.MONTH, 0 - time);
				calendar.set(Calendar.DAY_OF_MONTH, 1);
				// 清除相关数据
				if (ArrayUtils.isNotEmpty(indexs))
					delIndexData = perService.clearPerf(indexs, builder.TYPE,calendar.getTimeInMillis(),appIds);;
			}
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "清除应用系统性能数据失败...", e);
		}
		return delIndex && delIndexData;
	}

	@Override
	public List<ThresholdType> queryAlertThresholdType() {
		List<ThresholdType> thresholds = Lists.newArrayList();
		ConfigItem item = configItemService.getConfigItem(ThresholdTypeManager.THRESHOLDTYPE);
		if (item != null) {
			thresholds.addAll(JsonUtil.getInstance().json2List((String) item.getValue(), ThresholdType.class));
		}
		return thresholds;
	}

	@Override
	public float queryBaseApdex() {
		ConfigItem configItem = configItemService.getConfigItem("basic.apdex_t");
		if (configItem != null)
			return Float.valueOf((String) configItem.getValue());
		else
			return 0;
	}

	@Override
	public int ipFileUpload(List<IPLocation> iplist) {
		int i = 1;
		try {
			Map<String, Object> ipMap = new HashMap<String, Object>();
			for (IPLocation iplt : iplist) {
				if (ipLocationService.getIPLocation((com.broada.apm.model.IPLocation) BeanConvert.convertFrontObjToDataObj(iplt)).isEmpty()) {
					String objId = null;
					if (StringUtils.isNotBlank(iplt.getEndIp())) {
						objId = iplt.getStartIp() + "-" + iplt.getEndIp();
					} else {
						objId = iplt.getStartIp();
					}
					
					iplt.setId(objId);
					ipLocationService.addIPLocation(iplt.unwrap());
					ipMap.put(objId, iplt);
				}
			}
			if (ipMap.size() > 0) {
				indicatorService.NoticeCommand("reload", "area");
			}
		} catch (NoticeCommandException e) {
			i = 0;
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
		} catch (Exception e) {
			i = 0;
			log.error("ip导入失败", e);
		}
		return i;
	}

	@Override
	public int resolveL7Module(File file) throws Exception {
	    L7ModuleDescr l7moduleDescr = L7ModuleManager.resolveL7Module(file);
		L7Module module = l7moduleDescr.getModule();
        String l7_protoc = String.valueOf(module.getL7_proto());
		L7Module _l7module = l7ModuleService.getL7ModuleById(l7_protoc);
		// 模块存在且版本一致 提示模块已经存在
		if (_l7module != null && _l7module.getVersion().equals(module.getVersion())) {
			return 1;
			// 模块存在运行当中且导入版本不一致 提示先禁用模块
		} else if (_l7module != null && !_l7module.getVersion().equals(module.getVersion()) && _l7module.getStatus() == 0) {
			return 0;
		} else if (_l7module == null && !"1".equals(l7_protoc)) {
			if(l7ModuleService.getL7ModuleById("1") == null) return 6;
		}
		// 保存
		L7ModuleManager.saveL7Module(l7moduleDescr,file);
        CacheRefreshUtil.refresh(CacheRefreshUtil.REFRESH_PROTOCOL_CACHE);
		return 2;
	}

	private void logoReset() throws ApmDataIndicatorException {
		String picName = "logo.png";
		String defaultName = "default_logo.png";
		// 文件上传存放路径设置
		String saveDir = "../webapps/web/apps/main/img/";
		File srcFile = ApmFileUtils.getFile(saveDir + picName);
		File destFile = ApmFileUtils.getFile(saveDir + defaultName);
		if (destFile.exists()) {
			srcFile.delete();
			if (!destFile.renameTo(srcFile)) {
				log.error("logo还原失败");
				throw new ApmDataIndicatorException("logo还原失败");
			}
		}
	}

	@Override
	public int queryAllIPLocationSize() throws ApmDataIndicatorException {
		List<com.broada.apm.model.IPLocation> list = ipLocationService.getAllIPLocations();
		return list != null && list.size() > 0 ? list.size():0;
	}
}
